<?php


namespace App\Service\Cooperative;


use App\Constants\ErrorCode;
use App\Dao\CooperativeMenuDao;
use App\Dao\CooperativeRoleDao;
use App\Exception\BusinessException;
use App\Model\CooperativeMenu;
use App\Model\CooperativeRole;
use App\Model\CooperativeUser;
use App\Utils\Casbin;
use App\Utils\Log;
use Hyperf\Database\Model\Collection;
use Hyperf\DbConnection\Db;
use Hyperf\Di\Annotation\Inject;

class CooperativeRoleService extends BaseService
{
    /**
     * @Inject()
     * @var CooperativeRoleDao
     */
    protected $cooperativeRoleDao;

    /**
     * @Inject()
     * @var CooperativeMenuDao
     */
    protected $cooperativeMenuDao;

    /**
     * @var Casbin
     */
    protected $casbinInstance;

    public function __construct()
    {
        $this->casbinInstance = make(Casbin::class, [config('casbin.cooperative')]);
    }

    /**
     * @param array $where
     * @return \Hyperf\Contract\LengthAwarePaginatorInterface
     */
    public function index(array $where): \Hyperf\Contract\LengthAwarePaginatorInterface
    {
        $where['cooperative_id'] = $this->user()->cooperative_id;
        return $this->cooperativeRoleDao->paginate($where);
    }

    /**
     * @param $where
     * @return Collection
     */
    public function all($where): Collection
    {
        $where['cooperative_id'] = $this->user()->cooperative_id;
        return $this->cooperativeRoleDao->select($where);
    }

    /**
     * @param $id
     * @param array $data
     * @return CooperativeRole
     * @throws \Exception
     */
    public function save($id, array $data): CooperativeRole
    {
        if ($id) {
            /** @var CooperativeRole $role */
            $role = $this->cooperativeRoleDao->first(['id' => $id, 'cooperative_id' => $this->user()->cooperative_id]);
            if (!$role) {
                throw new BusinessException(ErrorCode::COOPERATIVE_ROLE_NOT_FOUND);
            }
            if ($role->name == config('menus.default_cooperative_role.name')) {
                throw new BusinessException(ErrorCode::COOPERATIVE_DEFAULT_ROLE_CANT_CHANGE);
            }
        } else {
            $role = new CooperativeRole();
        }

        /**
         * @var $role CooperativeRole
         */
        $role->fill($data);
        $role->cooperative_id = $this->user()->cooperative_id;

        Db::beginTransaction();
        try {
            $status = $role->save();
            if (!$status) {
                throw new BusinessException(ErrorCode::COOPERATIVE_ROLE_SAVE_ERROR);
            }

            //更新角色菜单权限
            $currentCooperativeMenuIds = $this->user()->cooperative->cooperativeMenus()->pluck('id')->toArray();
            $data['menus'] = array_intersect($currentCooperativeMenuIds, $data['menus']);
            $role->cooperativeMenus()->sync($data['menus']);

            $apiMenus = $role->cooperativeMenus()->get();

            $apiMenuApis = $apiMenus->pluck('api')->filter(
                function ($item) {
                    return $item != '';
                }
            )->toArray();

            //更新角色api访问权限
            $this->casbinInstance->setPermissionsForRole($role->id, $apiMenuApis);

            Db::commit();
        } catch (\Exception $exception) {
            Db::rollBack();
            Log::get()->error($exception->getMessage(), $data);
            throw $exception;
        }
        return $role;
    }

    public function delete(int $id): void
    {
        /** @var $role CooperativeRole */
        $role = $this->cooperativeRoleDao->first(['id' => $id,'cooperative_id' => $this->user()->cooperative_id]);
        if (!$role) {
            throw new BusinessException(ErrorCode::COOPERATIVE_ROLE_NOT_FOUND);
        }

        if ($role->name == config('menus.default_cooperative_role.name')) {
            throw new BusinessException(ErrorCode::COOPERATIVE_DEFAULT_ROLE_CANT_DEL);
        }

        Db::transaction(
            function () use ($role) {
                //删除角色菜单关联表数据
                $role->cooperativeMenus()->sync([]);

                //删除角色访问权限
                $this->casbinInstance->deleteRole($role->id);

                //删除角色
                $role->delete();
            }
        );
    }

    public function menus(int $id)
    {
        /** @var $role CooperativeRole */
        $role = $this->cooperativeRoleDao->first(['id' => $id,'cooperative_id' => $this->user()->cooperative_id]);

        $menuIds = $role->cooperativeMenus->pluck('id');
        return $menuIds;
    }

    /**
     * @param int $id
     * @return array
     */
    public function menuTree(): array
    {
        $menus = $this->cooperativeMenuDao->select(['cooperative_id' => $this->user()->cooperative_id]);
        $tree = $this->tree($menus);
        return $tree;
    }

    public function tree($menus, $pid = 0)
    {
        $tree = [];
        /** @var CooperativeMenu $menu */
        foreach ($menus as $menu) {
            if ($menu->pid == $pid) {
                $node = [];
                $node['id'] = $menu->id;
                $node['name'] = $menu->name;
                $node['title'] = $menu->title;
                $node['api'] = $menu->api;
                $node['type'] = $menu->type;
                $node['pid'] = $pid;
                $children = $this->tree($menus, $menu->menu_config_id);
                if (!empty($children)) {
                    $node['children'] = $children;
                }
                $tree[] = $node;
            }
        }
        return $tree;
    }


}